package com.eas.biz.service.statistic.impl;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.eas.biz.constants.BizConstants;
import com.eas.biz.dao.statistic.dataobject.BaseGradeStatisticDO;
import com.eas.biz.dao.statistic.dataobject.SchoolGradeStatisticDO;
import com.eas.biz.dao.statistic.dataobject.SchoolStatisticDO;
import com.eas.biz.dao.statistic.dataobject.SchoolStatisticQuery;
import com.eas.biz.dao.statistic.interfaces.SchoolGradeStatisticDao;
import com.eas.biz.dao.statistic.interfaces.SchoolStatisticDao;
import com.eas.biz.service.statistic.domain.GradeLevelCount;
import com.eas.biz.service.statistic.domain.SchoolStatistic;
import com.eas.biz.service.statistic.domain.SchoolSubjectStatistic;
import com.eas.biz.service.statistic.interfaces.SchoolStatisticService;
import com.eas.biz.service.statistic.query.StatisticServiceQuery;
import com.eas.biz.service.user.interfaces.SchoolService;

@Service("schoolStatisticService")
public class SchoolStatisticServiceImpl implements SchoolStatisticService {

    @Resource(name = "schoolCacheService")
    private SchoolService schoolService;

    @Autowired
    private SchoolStatisticDao schoolStatisticDao;

    @Autowired
    private SchoolGradeStatisticDao schoolGradeStatisticDao;

    public List<SchoolStatistic> getStatisticList(long areaId, long examId,
            StatisticServiceQuery queryInput) {
        List<SchoolStatistic> list = new LinkedList<SchoolStatistic>();
        boolean withSubjectStatistic = queryInput != null && queryInput.isWithSubjectStatistic();
        boolean withGradeStatistic = queryInput != null && queryInput.isWithGradeStatistic();
        SchoolStatisticQuery query = new SchoolStatisticQuery(queryInput);
        query.setAreaId(areaId);
        query.setExamId(examId);
        query.setSortBy(queryInput != null ? queryInput.getSortField() : null);
        query.setSort(queryInput != null ? queryInput.getSortOrder() : null);
        if (withSubjectStatistic) {
            List<SchoolStatisticDO> result = schoolStatisticDao.selectByQuery(query);
            if (result != null) {
                Map<Long, SchoolStatistic> schoolMap = new HashMap<Long, SchoolStatistic>();
                for (SchoolStatisticDO csDO : result) {
                    SchoolStatistic cs = schoolMap.get(csDO.getSchoolId());
                    if (cs == null) {
                        cs = buildSchoolStatistic(csDO, false);
                        schoolMap.put(csDO.getSchoolId(), cs);
                    }

                    if (BizConstants.TOTAL_SCORE_SUBJECT.equals(csDO.getSubject())) {
                        SchoolStatistic newStatistic = buildSchoolStatistic(csDO,
                                withGradeStatistic);
                        newStatistic.setSubjectMap(cs.getSubjectMap());
                        schoolMap.put(csDO.getSchoolId(), newStatistic);
                    } else {
                        SchoolSubjectStatistic css = buildSubjectStatistic(csDO, withGradeStatistic);
                        cs.addSubjectStatistic(css);
                    }
                }

                list.addAll(schoolMap.values());
            }
        } else {
            query.setSubject(BizConstants.TOTAL_SCORE_SUBJECT);

            List<SchoolStatisticDO> result = schoolStatisticDao.selectByQuery(query);
            if (result != null && result.size() > 0) {
                for (SchoolStatisticDO ssDO : result) {
                    list.add(buildSchoolStatistic(ssDO, withGradeStatistic));
                }
            }
        }
        return list;
    }

    public List<SchoolSubjectStatistic> getSubjectStatisticList(long areaId, long examId,
            String subject, StatisticServiceQuery queryInput) {
        List<SchoolSubjectStatistic> list = new LinkedList<SchoolSubjectStatistic>();
        boolean withGradeStatistic = queryInput != null && queryInput.isWithGradeStatistic();
        if (StringUtils.isBlank(subject)) {
            return list;
        }
        SchoolStatisticQuery query = new SchoolStatisticQuery(queryInput);
        query.setAreaId(areaId);
        query.setExamId(examId);
        query.setSubject(subject);
        query.setSortBy(queryInput != null ? queryInput.getSortField() : null);
        query.setSort(queryInput != null ? queryInput.getSortOrder() : null);
        List<SchoolStatisticDO> result = schoolStatisticDao.selectByQuery(query);
        if (result != null) {
            for (SchoolStatisticDO ssDO : result) {
                list.add(buildSubjectStatistic(ssDO, withGradeStatistic));
            }
        }
        return list;
    }

    public SchoolStatistic getStatistic(long schoolId, long examId, StatisticServiceQuery queryInput) {
        SchoolStatistic schoolStatistic = null;
        boolean withSubjectStatistic = queryInput != null && queryInput.isWithSubjectStatistic();
        boolean withGradeStatistic = queryInput != null && queryInput.isWithGradeStatistic();
        if (withSubjectStatistic) {
            SchoolStatisticQuery query = new SchoolStatisticQuery(queryInput);
            query.setSchoolId(schoolId);
            query.setExamId(examId);

            List<SchoolStatisticDO> list = schoolStatisticDao.selectByQuery(query);
            if (list != null) {
                Map<String, SchoolSubjectStatistic> subjectMap = new HashMap<String, SchoolSubjectStatistic>();
                for (SchoolStatisticDO csDO : list) {
                    if (BizConstants.TOTAL_SCORE_SUBJECT.equals(csDO.getSubject())) {
                        schoolStatistic = buildSchoolStatistic(csDO, withGradeStatistic);
                        continue;
                    }

                    SchoolSubjectStatistic subject = subjectMap.get(csDO.getSubject());
                    if (subject == null) {
                        subject = buildSubjectStatistic(csDO, withGradeStatistic);
                        subjectMap.put(subject.getSubject(), subject);
                    }
                }

                if (schoolStatistic != null) {
                    schoolStatistic.setSubjectMap(subjectMap);
                }
            }
        } else {
            SchoolSubjectStatistic subjectStatistic = getSubjectStatistic(schoolId, examId,
                    BizConstants.TOTAL_SCORE_SUBJECT, queryInput);
            if (subjectStatistic != null) {
                schoolStatistic = buildSchoolStatistic(subjectStatistic);
            }
        }
        return schoolStatistic;
    }

    public SchoolSubjectStatistic getSubjectStatistic(long schoolId, long examId, String subject,
            StatisticServiceQuery queryInput) {
        if (StringUtils.isBlank(subject)) {
            return null;
        }

        boolean withGradeStatistic = queryInput != null && queryInput.isWithGradeStatistic();
        SchoolStatisticQuery query = new SchoolStatisticQuery(queryInput);
        query.setSchoolId(schoolId);
        query.setExamId(examId);
        query.setSubject(subject);
        List<SchoolStatisticDO> list = schoolStatisticDao.selectByQuery(query);
        if (list != null && list.size() > 0) {
            return buildSubjectStatistic(list.get(0), withGradeStatistic);
        } else {
            return null;
        }
    }

    public List<SchoolSubjectStatistic> getSubjectStatistic(List<Long> schoolIdList, long examId,
            String subject, StatisticServiceQuery queryInput) {
        List<SchoolSubjectStatistic> list = new LinkedList<SchoolSubjectStatistic>();
        if (StringUtils.isBlank(subject)) {
            return list;
        }

        boolean withGradeStatistic = queryInput != null && queryInput.isWithGradeStatistic();
        SchoolStatisticQuery query = new SchoolStatisticQuery(queryInput);
        query.setSchoolIdList(schoolIdList);
        query.setExamId(examId);
        query.setSubject(subject);
        List<SchoolStatisticDO> result = schoolStatisticDao.selectByQuery(query);
        if (result != null) {
            for (SchoolStatisticDO ssDO : result) {
                list.add(buildSubjectStatistic(ssDO, withGradeStatistic));
            }
        }
        return list;
    }

    public List<GradeLevelCount> getGradeList(long examId, long schoolId, String subject) {
        if (StringUtils.isBlank(subject)) {
            return null;
        }

        List<GradeLevelCount> gradeList = new LinkedList<GradeLevelCount>();
        SchoolStatisticQuery query = new SchoolStatisticQuery(null);
        query.setSchoolId(schoolId);
        query.setExamId(examId);
        query.setSubject(subject);
        List<SchoolGradeStatisticDO> list = schoolGradeStatisticDao.selectByQuery(query);
        if (gradeList != null) {
            for (BaseGradeStatisticDO grade : list) {
                gradeList.add(buildGradeLevelCount(grade));
            }
        }
        return gradeList;
    }

    public List<GradeLevelCount> getGradeList(long examId, long schoolId) {
        return getGradeList(examId, schoolId, BizConstants.TOTAL_SCORE_SUBJECT);
    }

    private SchoolStatistic buildSchoolStatistic(SchoolSubjectStatistic subjectStatistic) {
        SchoolStatistic cs = new SchoolStatistic();
        cs.setAreaId(subjectStatistic.getAreaId());
        cs.setSchoolId(subjectStatistic.getSchoolId());
        cs.setExamId(subjectStatistic.getExamId());
        cs.setStudentCount(subjectStatistic.getStudentCount());
        cs.setAvgScore(subjectStatistic.getAvgScore());
        cs.setMaxScore(subjectStatistic.getMaxScore());
        cs.setMinScore(subjectStatistic.getMinScore());
        cs.setStandardDiviation(subjectStatistic.getStandardDiviation());
        cs.setGradeList(subjectStatistic.getGradeList());
        cs.setLevelMap(subjectStatistic.getLevelMap());
        cs.setSchoolInfo(subjectStatistic.getSchoolInfo());
        return cs;
    }

    private SchoolStatistic buildSchoolStatistic(SchoolStatisticDO statisticDO,
            boolean withGradeStatistic) {
        SchoolStatistic cs = new SchoolStatistic();
        cs.setAreaId(statisticDO.getAreaId());
        cs.setSchoolId(statisticDO.getSchoolId());
        cs.setExamId(statisticDO.getExamId());
        cs.setStudentCount(statisticDO.getStudentCount());
        cs.setAvgScore(statisticDO.getAvgScore());
        cs.setMaxScore(statisticDO.getMaxScore());
        cs.setMinScore(statisticDO.getMinScore());
        cs.setStandardDiviation(statisticDO.getDiviation());
        cs.setSchoolInfo(schoolService.getSchoolInfo(statisticDO.getSchoolId()));
        if (withGradeStatistic) {
            cs.setGradeList(getGradeList(cs.getExamId(), cs.getSchoolId(),
                    BizConstants.TOTAL_SCORE_SUBJECT));
            cs.buildLevelMap();
        }
        return cs;
    }

    private GradeLevelCount buildGradeLevelCount(BaseGradeStatisticDO grade) {
        GradeLevelCount count = new GradeLevelCount();
        count.setLevel(grade.getLevel());
        count.setScore(grade.getScore());
        count.setCount(grade.getCount());
        return count;
    }

    private SchoolSubjectStatistic buildSubjectStatistic(SchoolStatisticDO schoolStatisticDO,
            boolean withGradeStatistic) {
        SchoolSubjectStatistic subject = new SchoolSubjectStatistic();
        subject.setAreaId(schoolStatisticDO.getAreaId());
        subject.setSchoolId(schoolStatisticDO.getSchoolId());
        subject.setExamId(schoolStatisticDO.getExamId());
        subject.setSubject(schoolStatisticDO.getSubject());
        subject.setStudentCount(schoolStatisticDO.getStudentCount());
        subject.setAvgScore(schoolStatisticDO.getAvgScore());
        subject.setMaxScore(schoolStatisticDO.getMaxScore());
        subject.setMinScore(schoolStatisticDO.getMinScore());
        subject.setStandardDiviation(schoolStatisticDO.getDiviation());
        subject.setSchoolInfo(schoolService.getSchoolInfo(schoolStatisticDO.getSchoolId()));
        if (withGradeStatistic) {
            subject.setGradeList(getGradeList(subject.getExamId(), subject.getSchoolId(),
                    subject.getSubject()));
            subject.buildLevelMap();
        }
        return subject;
    }
}
